//
//  VocTest.cpp
//  gre
//
//  Created by Kutlak Roman on 11/03/2012.
//  Copyright (c) 2012 University of Aberdeen. All rights reserved.
//

#include <cstdio>

#include <sstream>
#include <iostream>
#include <thread>

#include <gtest/gtest.h>

#include "Voc.h"

using namespace std;
using namespace kutlak::roman::gre;

void do_instance();

void do_instance() 
{    Voc& v = Voc::Instance();
    v.NumWords();
}

TEST(Voc, Instance) 
{    for (unsigned i = 0; i < 5; ++i) 
{        // check that taking instance is safe and only one instance is created.
    thread t1(do_instance);
    thread t2(do_instance);
    thread t3(do_instance);
    thread t4(do_instance);
    thread t5(do_instance);
    
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
}
}

TEST(Voc, Index) 
{    Voc& v = Voc::Instance();
    Vindex_t red = v.Index("red");
    string s("attrx");
    Vindex_t sa = v.Index(s);
    
    EXPECT_LT(0, red);
    EXPECT_EQ(red, v.Index("red"));
    
    EXPECT_EQ(sa, v.Index("attrx"));
    
    EXPECT_EQ(v.Index("colour_attribute"), 
              v.Index("colour_attribute"));
    
    EXPECT_EQ("red", v.String(red));
}

TEST(Voc, NWords) 
{    Voc& v = Voc::Instance();
    Vindex_t attr = v.Index("yellowcoloured");
    Vindex_t start = v.NumWords();
    Vindex_t current = v.NumWords();
    
    
    v.String(attr);
    current = v.NumWords();
    EXPECT_EQ(start, current);
    
    v.String(attr*2);
    current = v.NumWords();
    EXPECT_EQ(start, current);
    
    v.Index("yellowcoloured");
    current = v.NumWords();
    EXPECT_EQ(start, current);
    
    v.Index("yellowcoloured2");
    current = v.NumWords();
    EXPECT_LT(start, current);
}

TEST(Voc, Serialisation) 
{    Voc& v = Voc::Instance();
    Vindex_t lastAttr = v.Index("last attr");
    
    Vindex_t nWords = v.NumWords();
    
    stringstream ss;
    stringstream errorSs;
    
    EXPECT_EQ(0, ss.str().length());
    
    ss << v;
    errorSs << "<vocab>\nError stream.\n";
    
    EXPECT_LT(0, ss.str().length());
    
    try 
    {        // exception safte should guarantee that this will not mess up our class
        errorSs >> v;
        EXPECT_EQ(true, false); // the above should throw...
    } 
    catch (DeserialisationException& e) 
    {        cerr << e.what() << "\n\t" << e.data() << endl;
    }
    
    EXPECT_EQ(nWords, v.NumWords());
    
    v.Index("latest attr");
    EXPECT_EQ(lastAttr, v.Index("last attr"));
    
    
    // now this actually changes the PF
    try 
    {        ss >> v;
    } 
    catch (DeserialisationException& e) 
    {        cerr << e.what() << "\n\t" << e.data() << endl;
        EXPECT_EQ(true, false); // the above should NOT throw...
        cerr << ss.str() << endl;
    }
    
    EXPECT_EQ(nWords, v.NumWords());
    
    v.Index("latest attr");
    EXPECT_EQ(lastAttr, v.Index("last attr"));
}
